/*
 * Copyright (c) 2014,KJFrameForAndroid Open Source Project,张涛.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.yyfax.common.tools;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.MemoryInfo;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.ActivityManager.RunningServiceInfo;
import android.app.KeyguardManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.NetworkInfo.State;
import android.net.Uri;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.view.inputmethod.InputMethodManager;
import com.yyfax.common.CLog;

import java.io.File;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;

/**
 * 系统信息工具包<br>
 * <p>
 * <b>创建时间</b> 2014-8-14
 *
 * @author kymjs (https://github.com/kymjs)
 * @version 1.1
 */
@SuppressLint("SimpleDateFormat")
public final class SystemTool {
	private static final String TAG = "SystemTool";

	/**
	 * 指定格式返回当前系统时间
	 */
	public static String getDataTime(String format) {
		SimpleDateFormat df = new SimpleDateFormat(format);
		return df.format(new Date());
	}

	/**
	 * 返回当前系统时间(格式以HH:mm形式)
	 */
	public static String getDataTime() {
		return getDataTime("HH:mm");
	}

	/**
	 * 获取手机IMEI码，需要适配动态授权
	 */
	public static String getPhoneIMEI(Context cxt) {
		TelephonyManager tm = (TelephonyManager) cxt.getSystemService(Context.TELEPHONY_SERVICE);
		return tm.getDeviceId();
	}

	/**
	 * 获取手机系统SDK版本
	 * @return 如API 17 则返回 17
	 */
	public static int getSDKVersion() {
		return android.os.Build.VERSION.SDK_INT;
	}

	/**
	 * 获取系统版本
	 * @return 形如2.3.3
	 */
	public static String getSystemVersion() {
		return android.os.Build.VERSION.RELEASE;
	}

	/**
	 * 调用系统发送短信
	 */
	public static void sendSMS(Context cxt, String smsBody) {
		Uri smsToUri = Uri.parse("smsto:");
		Intent intent = new Intent(Intent.ACTION_SENDTO, smsToUri);
		intent.putExtra("sms_body", smsBody);
		cxt.startActivity(intent);
	}

	/**
	 * 判断网络是否连接
	 */
	public static boolean checkNet(Context context) {
		ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
		NetworkInfo info = cm.getActiveNetworkInfo();
		return info != null;// 网络是否连接
	}

//	/**
//	 * 仅wifi联网功能是否开启
//	 */
//	public static boolean checkOnlyWifi(Context context) {
//		if (PreferenceHelper.readBoolean(context, KJConfig.SETTING_FILE, KJConfig.ONLY_WIFI)) {
//			return isWiFi(context);
//		} else {
//			return true;
//		}
//	}

	/**
	 * 判断是否为wifi联网
	 */
	public static boolean isWiFi(Context cxt) {
		ConnectivityManager cm = (ConnectivityManager) cxt.getSystemService(Context.CONNECTIVITY_SERVICE);
		// wifi的状态：ConnectivityManager.TYPE_WIFI
		// 3G的状态：ConnectivityManager.TYPE_MOBILE
		State state = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState();
		return State.CONNECTED == state;
	}

	/**
	 * 隐藏系统键盘
	 * <br>
	 * <b>警告</b> 必须是确定键盘显示时才能调用
	 */
	public static void hideKeyBoard(Activity aty) {
		((InputMethodManager) aty.getSystemService(Context.INPUT_METHOD_SERVICE)).hideSoftInputFromWindow(aty.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
	}

	/**
	 * 判断当前应用程序是否后台运行
	 */
	public static boolean isBackground(Context context) {
		ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
		List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
		for (RunningAppProcessInfo appProcess : appProcesses) {
			if (appProcess.processName.equals(context.getPackageName())) {
				if (appProcess.importance == RunningAppProcessInfo.IMPORTANCE_BACKGROUND) {
					// 后台运行
					return true;
				} else {
					// 前台运行
					return false;
				}
			}
		}
		return false;
	}

	/**
	 * 判断手机是否处理睡眠
	 */
	public static boolean isSleeping(Context context) {
		KeyguardManager kgMgr = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
		boolean isSleeping = kgMgr.inKeyguardRestrictedInputMode();
		return isSleeping;
	}

	/**
	 * 安装apk
	 */
	public static void installApk(Context context, File file) {
		Intent intent = new Intent();
		intent.setAction("android.intent.action.VIEW");
		intent.addCategory("android.intent.category.DEFAULT");
		intent.setType("application/vnd.android.package-archive");
		intent.setData(Uri.fromFile(file));
		intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
		intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		context.startActivity(intent);
	}

	/**
	 * 获取当前应用程序的版本号
	 */
	public static String getAppVersionName(Context context) {
		String version = "0";
		try {
			version = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
		} catch (NameNotFoundException e) {
			throw new RuntimeException(SystemTool.class.getName() + "the application not found");
		}
		return version;
	}

	/**
	 * 获取当前应用程序的版本号
	 */
	public static int getAppVersionCode(Context context) {
		int version = 0;
		try {
			version = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode;
		} catch (NameNotFoundException e) {
			throw new RuntimeException(SystemTool.class.getName() + "the application not found");
		}
		return version;
	}

	/**
	 * 回到home，后台运行
	 */
	public static void goHome(Context context) {
		Intent mHomeIntent = new Intent(Intent.ACTION_MAIN);
		mHomeIntent.addCategory(Intent.CATEGORY_HOME);
		mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
		context.startActivity(mHomeIntent);
	}

	/**
	 * 获取应用签名
	 */
	public static String getSign(Context context, String pkgName) {
		try {
			PackageInfo pis = context.getPackageManager().getPackageInfo(pkgName, PackageManager.GET_SIGNATURES);
			return hexdigest(pis.signatures[0].toByteArray());
		} catch (NameNotFoundException e) {
			throw new RuntimeException(SystemTool.class.getName() + "the " + pkgName + "'s application not found");
		}
	}

	/**
	 * 将签名字符串转换成需要的32位签名
	 */
	private static String hexdigest(byte[] paramArrayOfByte) {
		final char[] hexDigits = {48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102};
		try {
			MessageDigest localMessageDigest = MessageDigest.getInstance("MD5");
			localMessageDigest.update(paramArrayOfByte);
			byte[] arrayOfByte = localMessageDigest.digest();
			char[] arrayOfChar = new char[32];
			for (int i = 0, j = 0; ; i++, j++) {
				if (i >= 16) {
					return new String(arrayOfChar);
				}
				int k = arrayOfByte[i];
				arrayOfChar[j] = hexDigits[(0xF & k >>> 4)];
				arrayOfChar[++j] = hexDigits[(k & 0xF)];
			}
		} catch (Exception e) {
		}
		return "";
	}

	/**
	 * 获取设备的可用内存大小
	 * @param cxt 应用上下文对象context
	 * @return 当前内存大小
	 */
	public static int getDeviceUsableMemory(Context cxt) {
		ActivityManager am = (ActivityManager) cxt.getSystemService(Context.ACTIVITY_SERVICE);
		MemoryInfo mi = new MemoryInfo();
		am.getMemoryInfo(mi);
		// 返回当前系统的可用内存
		return (int) (mi.availMem / (1024 * 1024));
	}

	public static String getCurrentProcessName(Context context) {
		int pid = android.os.Process.myPid();
		ActivityManager mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
		List<RunningAppProcessInfo> list = mActivityManager.getRunningAppProcesses();
		for (RunningAppProcessInfo appProcess : list) {
			if (appProcess.pid == pid) {
				return appProcess.processName;
			}
		}
		return "Unknown_ProcessName";
	}

	/**
	 * 清理后台进程与服务
	 * @param cxt 应用上下文对象context
	 * @return 被清理的数量
	 */
	public static int gc(Context cxt) {
		long i = getDeviceUsableMemory(cxt);
		int count = 0; // 清理掉的进程数
		ActivityManager am = (ActivityManager) cxt.getSystemService(Context.ACTIVITY_SERVICE);
		// 获取正在运行的service列表
		List<RunningServiceInfo> serviceList = am.getRunningServices(100);
		if (serviceList != null) {
			int pid = android.os.Process.myPid();
			for (RunningServiceInfo service : serviceList) {
				if (service.pid == pid)
					continue;
				try {
					android.os.Process.killProcess(service.pid);
					count++;
				} catch (Exception e) {
					e.getStackTrace();
					continue;
				}
			}
		}

		// 获取正在运行的进程列表
		List<RunningAppProcessInfo> processList = am.getRunningAppProcesses();
		if (processList != null) {
			for (RunningAppProcessInfo process : processList) {
				// 一般数值大于RunningAppProcessInfo.IMPORTANCE_SERVICE的进程都长时间没用或者空进程了
				// 一般数值大于RunningAppProcessInfo.IMPORTANCE_VISIBLE的进程都是非可见进程，也就是在后台运行着
				if (process.importance > RunningAppProcessInfo.IMPORTANCE_VISIBLE) {
					// pkgList 得到该进程下运行的包名
					String[] pkgList = process.pkgList;
					for (String pkgName : pkgList) {
						CLog.d(TAG, "======killing package name：" + pkgName);
						try {
							am.killBackgroundProcesses(pkgName);
							count++;
						} catch (Exception e) { // 防止意外发生
							e.getStackTrace();
							continue;
						}
					}
				}
			}
		}
		CLog.d(TAG, "clean up" + (getDeviceUsableMemory(cxt) - i) + "M memory");
		return count;
	}

	/**
	 * Android中的堆内存分为Native Heap和Dalvik Heap。
	 * C/C++申请的内存空间在Native Heap中，Java申请的内存空间则在Dalvik Heap中。
	 *
	 * 对于head堆的大小限制，可以查看/system/build.prop文件：
	 * dalvik.vm.heapstartsize=8m
	 * dalvik.vm.heapgrowthlimit=96m
	 * dalvik.vm.heapsize=256m
	 *
	 * heapsize参数表示单个进程heap可用的最大内存，
	 * 但如果存在以下参数”dalvik.vm.headgrowthlimit=96m”表示单个进程heap内存被限定在96m，
	 * 即程序运行过程实际只能使用96m内存。
	 */
	public static int maxHeadSize(Context ctx) {
		ActivityManager activityManager = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
		return activityManager.getMemoryClass();
	}

	/**
	 * 如果获取不到MAC地址，则返回一个硬编码的地址0a00aa0aaa00
	 */
	public static String getMacAddress() {
		String mac_s = "";
		try {
			byte[] mac;
			NetworkInterface ne = NetworkInterface.getByInetAddress(InetAddress.getByName(getLocalIpAddress()));
			mac = ne.getHardwareAddress();
			mac_s = byte2hex(mac);
		} catch (Exception e) {
			mac_s = "0a00aa0aaa00";
		}
		return mac_s;
	}

	private static String getLocalIpAddress() {
		try {
			for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) {
				NetworkInterface intf = en.nextElement();
				for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) {
					InetAddress inetAddress = enumIpAddr.nextElement();
					if (!inetAddress.isLoopbackAddress()) {
						return inetAddress.getHostAddress().toString();
					}
				}
			}
		} catch (SocketException ex) {
			return "";
		}
		return "";
	}

	private static String byte2hex(byte[] b) {
		StringBuffer hs = new StringBuffer(b.length);
		String stmp = "";
		int len = b.length;
		for (int n = 0; n < len; n++) {
			stmp = Integer.toHexString(b[n] & 0xFF);
			if (stmp.length() == 1)
				hs = hs.append("0").append(stmp);
			else {
				hs = hs.append(stmp);
			}
		}
		return String.valueOf(hs);
	}

	/**
	 * 检测是否打开模拟位置选项
	 * @return returns true if mock location enabled, false if not enabled.
	 */
	public static boolean isMockSettingsON(Context context) {
		String allowMock = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ALLOW_MOCK_LOCATION);
		return !"0".equals(allowMock);
	}

	/**
	 * 检测安装的应用中是否有应用使用了android.permission.ACCESS_MOCK_LOCATION权限
	 * @return returns true if installed application has the android.permission.ACCESS_MOCK_LOCATION permission
	 */
	public static boolean areThereMockPermissionApps(Context context) {
		int count = 0;
		PackageManager pm = context.getPackageManager();
		List<ApplicationInfo> packages = pm.getInstalledApplications(PackageManager.GET_META_DATA);
		for (ApplicationInfo applicationInfo : packages) {
			try {
				PackageInfo packageInfo = pm.getPackageInfo(applicationInfo.packageName, PackageManager.GET_PERMISSIONS);
				String[] requestedPermissions = packageInfo.requestedPermissions;// Get Permissions
				if (requestedPermissions != null) {
					for (String requestedPermission : requestedPermissions) {
						if (requestedPermission.equals("android.permission.ACCESS_MOCK_LOCATION")
								&& !applicationInfo.packageName.equals(context.getPackageName())) {
							count++;
						}
					}
				}
			} catch (NameNotFoundException e) {
				CLog.e(TAG, "Got exception " + e.getMessage());
			}
		}
		return count > 0;
	}
}